/* (C) Copyright 2008 Bill Buckels */

/* What Time is It - Apple Version by Bill Buckels */
/* root module                                     */

/* June, 1991         */
/* version 1.0        */
/* English Modules... */
/* French Modules followed shortly thereafter */

#include <stdio.h>
#include <fcntl.h>
#include <prodos.h>
#include <sgtty.h>
#include <device.h>
#include <sysfunc.h>

#define TEXTMODE  0
#define GRAFMODE  2  /* graphics only */

int randomseed =0;

int randomhours[5];
int randomminutes[5];
int hourslimit=12;

int getch();
int randomval();

/* special keys as noted */
/* note that none of the special keys used are affected by caps lock */

#define ESCKEY     27        /* exit current module */
#define ENTERKEY   13        /* initialize command  */
#define SPACEBAR   32        /* same as ENTERKEY    */
#define SOUNDKEY   19        /* sound toggle */

#define THREE      51
#define FIVE       53
int multiples = 3;

/* the limits for the multiple choices - default is set to 3 boxes */
/* pressing the number 3 or 5 prior to pressing the spacebar       */
/* or the enter key will flipflop between levels                   */

#define BACKSPACE  8
#define LEFTARROW  8
#define RIGHTARROW 21
#define UPARROW    11
#define DOWNARROW  10
#define DELETE     127
#define CTRLKEY    -64  /* toupper - 64 = ctrl value of a key press */

#define ON  1
#define OFF 0
int soundflag = ON;
#define ENGLISH 0
#define FRENCH  1

#define PUT 0    /* action verbs for putimage */
#define GET 1
#define P_AND 5



/* the auxmem (ems) library info */
/* graphics library map for library TIME.RIB */


#define TIME_SIZE 26838 /* library size in bytes */


/* lib info for character array created from fragment HOURMENU.BOT */
#define HOURMENU_SIZE   7680
#define HOURMENU_WIDTH  40
#define HOURMENU_HEIGHT 192
#define HOURMENU_OFFSET 0

/* lib info for character array created from fragment TIME0A.RAG */
#define TIME0A_SIZE   1296
#define TIME0A_WIDTH  16
#define TIME0A_HEIGHT 81
#define TIME0A_OFFSET 7680

/* lib info for character array created from fragment TIME1A.RAG */
#define TIME1A_SIZE   3276
#define TIME1A_WIDTH  26
#define TIME1A_HEIGHT 126
#define TIME1A_OFFSET 8976

/* lib info for character array created from fragment TIME2A.RAG */
#define TIME2A_SIZE   3264
#define TIME2A_WIDTH  24
#define TIME2A_HEIGHT 136
#define TIME2A_OFFSET 12252

/* lib info for character array created from fragment ELBOW.RAG */
#define ELBOW_SIZE   96
#define ELBOW_WIDTH  4
#define ELBOW_HEIGHT 24
#define ELBOW_OFFSET 15516

/* lib info for character array created from fragment ELBOW2.RAG */
#define ELBOW2_SIZE   96
#define ELBOW2_WIDTH  4
#define ELBOW2_HEIGHT 24
#define ELBOW2_OFFSET 15612

/* lib info for character array created from fragment DOWNPIPE.RAG */
#define DOWNPIPE_SIZE   64
#define DOWNPIPE_WIDTH  4
#define DOWNPIPE_HEIGHT 16
#define DOWNPIPE_OFFSET 15708

/* lib info for character array created from fragment DOWN2.RAG */
#define DOWN2_SIZE   64
#define DOWN2_WIDTH  4
#define DOWN2_HEIGHT 16
#define DOWN2_OFFSET 15772

/* lib info for character array created from fragment SPOUT.RAG */
#define SPOUT_SIZE   496
#define SPOUT_WIDTH  16
#define SPOUT_HEIGHT 31
#define SPOUT_OFFSET 15836

/* lib info for character array created from fragment SPOUT2.RAG */
#define SPOUT2_SIZE   496
#define SPOUT2_WIDTH  16
#define SPOUT2_HEIGHT 31
#define SPOUT2_OFFSET 16332

/* lib info for character array created from fragment WAVE.RAG */
#define WAVE_SIZE   1704
#define WAVE_WIDTH  24
#define WAVE_HEIGHT 71
#define WAVE_OFFSET 16828

/* lib info for character array created from fragment WAVENO.RAG */
#define WAVENO_SIZE   1704
#define WAVENO_WIDTH  24
#define WAVENO_HEIGHT 71
#define WAVENO_OFFSET 18532

/* lib info for character array created from fragment BOTGLAS.RAG */
#define BOTGLAS_SIZE   580
#define BOTGLAS_WIDTH  10
#define BOTGLAS_HEIGHT 58
#define BOTGLAS_OFFSET 20816

/* lib info for character array created from fragment TIME1B.RAG */
#define TIME1B_SIZE   968
#define TIME1B_WIDTH  22
#define TIME1B_HEIGHT 44
#define TIME1B_OFFSET 21396

/* lib info for character array created from fragment TIME1C.RAG */
#define TIME1C_SIZE   968
#define TIME1C_WIDTH  22
#define TIME1C_HEIGHT 44
#define TIME1C_OFFSET 22364

/* lib info for character array created from fragment TIME1D.RAG */
#define TIME1D_SIZE   912
#define TIME1D_WIDTH  16
#define TIME1D_HEIGHT 57
#define TIME1D_OFFSET 23332

/* lib info for character array created from fragment TOPGLAS.RAG */
#define TOPGLAS_SIZE   580
#define TOPGLAS_WIDTH  10
#define TOPGLAS_HEIGHT 58
#define TOPGLAS_OFFSET 24244

/* lib info for character array created from fragment WORM0.RAG */
#define WORM0_SIZE   408
#define WORM0_WIDTH  8
#define WORM0_HEIGHT 51
#define WORM0_OFFSET 24824

/* lib info for character array created from fragment WORM1.RAG */
#define WORM1_SIZE   408
#define WORM1_WIDTH  8
#define WORM1_HEIGHT 51
#define WORM1_OFFSET 25232

/* lib info for character array created from fragment WORM2.RAG */
#define WORM2_SIZE   408
#define WORM2_WIDTH  8
#define WORM2_HEIGHT 51
#define WORM2_OFFSET 25640

/* lib info for character array created from fragment LIGHTON.RAG */
#define LIGHTON_SIZE   76
#define LIGHTON_WIDTH  4
#define LIGHTON_HEIGHT 19
#define LIGHTON_OFFSET 26048

/* lib info for character array created from fragment LIGHTOFF.RAG */
#define LIGHTOFF_SIZE   76
#define LIGHTOFF_WIDTH  4
#define LIGHTOFF_HEIGHT 19
#define LIGHTOFF_OFFSET 26124

/* lib info for character array created from fragment TIME2B.RAG */
#define TIME2B_SIZE   638
#define TIME2B_WIDTH  22
#define TIME2B_HEIGHT 29
#define TIME2B_OFFSET 26200




#define clearscreen() setmem(0x4000,0x2000,0x80)

/* lib info for character array created from fragment NOTE.RAG */
#define NOTE_SIZE   44
#define NOTE_WIDTH  2
#define NOTE_HEIGHT 22
#define NOTE_OFFSET 1050
#define NOTEBACK_OFFSET 1094

/* screen coordinates */
#define NOTEX 38
#define NOTEY 169

/* pointer to the base address of the library    */
/* use globals... avoid initializing common data */
/* repeatedly... */

char *SNAIL=(char *)4192;

/* use a buffer directly beneath the program */
/* to back-up the clock face                 */
/* buffer size is 640 bytes....              */
/* this can also be used as a scratchpad for other purposes */

char *cleanface=(char *)7552;

#define  FACEX 12
#define  FACEY 56
#define  FACEHEIGHT 56
#define  FACEWIDTH  10

char *NOTE;
char *NOTEBACK;

#define SNAIL_SIZE 1522 /* library size in bytes */

#define SNL_SIZE   350
#define SNL_WIDTH  10
#define SNL_HEIGHT 35

char *SNLBACK;
char *LEFTSNL;
char *RIGHTSNL;


main()
{

   int position=0,oldposition=0,c,answers;

      /* set globals here */
      NOTE= (char *)&SNAIL[NOTE_OFFSET];
      NOTEBACK= (char *)&SNAIL[NOTEBACK_OFFSET];
      SNLBACK= (char *)&SNAIL[700];
      LEFTSNL= (char *)&SNAIL[0];
      RIGHTSNL= (char *)&SNAIL[350];


   /* keep initialization stuff out of the way   */
   /* group our basic initialization stuff       */
   /* like setting the graphics mode and loading */
   /* the font set into CINIT.OVR                */

  ovloader("CINIT",GRAFMODE);

  RESTART:;

   /* load the auxmem (ems) libraries etc with the PLOGO.OVR overlay. */
   /* a key press is returned from PLOGO and if it is not    */
   /* the ESCAPE KEY we continue... otherwise we exit by     */
   /* calling CINIT.OVR to reset to text mode and exit.      */

   /* try to keep the main module as lean as possible    */
   /* but at the same time use the important functions   */
   /* that will be required by the module overlays to    */
   /* avoid making them any bigger than they need to be. */


   if(ovloader("PLOGO","TIME.SYSTEM","TIME.RIB",TIME_SIZE,ENGLISH)==ESCKEY)
      ovloader("CINIT",TEXTMODE);

   RECOVER:;

   /* put the first menu screen into place */
   emsputimage(0,40,192,0,0,0);
   multiples=3;

   /* set the startup flag and save the screen beneath position 0  */
   /* then put the first snail in place and move him based on the  */
   /* keys that are pressed.                                       */

   /* the main menu was moved into an overlay to conserve space    */

   /* BUT-  */
   /* somewhat of a time penalty is extracted in the extra DISK IO */
   /* required by the use of overlays. By updating the screens     */
   /* reasonably quickly and keeping our overlays small we can     */
   /* balance our real time sequencing to gloss this over.         */


   position=ovloader("MAINMENU",oldposition);
   oldposition=position;
   answers=0;

     do
     {
     switch(position)
     {
        /* load the overlays or restart the program    */
        /* we can do multiple overlays for each module */
        /* here... reward overlays... animation etc.   */

        case 2 :  c=ovloader("TIME2",answers);break;
        case 1 :  c=ovloader("TIME1",answers);break;
        case 0 :  c=ovloader("TIME0",answers);break;

        default:  goto RESTART;
        }

       answers=c;
       multiples=5;

       /* do the rewards */
       if(answers==10 || answers == 20)
       {
          switch(position)
          {

        case 2 :  ovloader("TIME2A");break;
        case 1 :  ovloader("TIME1A");break;
        case 0 :  ovloader("TIME0A");break;
          }
       }
       /* end of round */
       if(answers==20)c=0;

    }while(c!=0);

    goto  RECOVER;

}


/* the functions below are intrinsic to this program and  */
/* over-ride or replace library functions...              */
/* since they are called by all the modules they are kept */
/* in the ROOT SEGMENT                                    */

/* by putting noteworthy into the root with the sound function   */
/* and the putimage function, we avoid needing to load this code */
/* again... It is used by all modules...                         */

noteworthy(startflag)
int startflag;
{

    if(startflag) /* if we are starting a new menu then save */
    {             /* the area behind the note                */
     putimage(NOTEBACK,NOTE_WIDTH,NOTE_HEIGHT,NOTEX,NOTEY,GET);
    }
    else          /* if we are not just starting then toggle the sound */
    {
     /* make a tiny sound... */
     /* this gets the sound function into the root */
     sound(3,0,1);
     if(soundflag)soundflag=OFF;
     else soundflag=ON;
     }

    /* restore the screen behind the note if the soundflag is off */
    /* otherwise display the musical note.                        */

    if(!soundflag)
      putimage(NOTEBACK,NOTE_WIDTH,NOTE_HEIGHT,NOTEX,NOTEY,PUT);
    else
      putimage(NOTE,NOTE_WIDTH,NOTE_HEIGHT,NOTEX,NOTEY,P_AND);


}

/* randomize 5 sets of hours and 5 sets of minutes  */
/* return the selected answer from the group        */
/* we must make certain that there is no repetition */
/* in groups of 5 hours.                            */


char hourseed[50]=
    {
      /* first group for 1-12 hours */
      2,  11, 10, 8,  6,
      1,  7,  9,  5, 10,
      3,  12, 1,  4,  6,
      8,  3,  5,  7,  9,
      6,  4, 12,  8,  1,

      /* second group for 13-24 hours mixed with 1-12 hours */
      14,  11, 22,  5,   20,
      1,   19,  9,  17,  10,
      3,   24,  1,  16,  6,
      8,   13, 15,  7,   23,
      16,  4,  12,  8,   21};


/* a variety of minute values... */
int minuteseed[25]={
      5,  0,  10, 55, 15,
      45, 20, 35, 30, 25,
      15, 35, 10, 40, 5,
      45, 0,  50, 55, 10,
      20, 35, 40, 15, 55};

randomval()
{
    int i,temp,temp2;

   /* there are either 25 or 50 hours choices               */
   /* if we pick them sequentially there will be no repeats */
   /* they have been shuffled fairly well.                  */

   if(hourslimit==12)temp=24;
   else temp=49;

   temp2=temp-24;

    for(i=0;i<5;i++)
    {
      randomseed++;
      if(randomseed>temp)randomseed=temp2;
      randomhours[i]=(int)hourseed[randomseed];
      }


    /* get one of the 25 minute choices */
    randomseed+=randomhours[0];
    temp=24;

    for(i=0;i<5;i++)
    {
      randomseed++;
      if(randomseed>temp)randomseed=0;
      randomminutes[i]=(int)minuteseed[randomseed];
      }

    /* return an answer within the range of questions */
    return randomhours[0]%multiples;
}

getch()
{
  char *KEYPRESS = (char*)0xC000;           /* return the last key press  */
  char *KEYCLEAR = (char*)0xC010;           /* clear the last key press   */
  char c;
  char temp;

   if(hourslimit==12)temp=24;
   else temp=49;

            /* clear stragglers from the keyboard buffer */
            while((c=KEYPRESS[0]) > 127)
            {
                KEYCLEAR[0]=0;
                randomseed++;
                }
            /* read the keyboard buffer    */
            /* and return the character    */
            do{
                randomseed++;
                if(randomseed>temp)randomseed=0;
                c = KEYPRESS[0];

               }while(c < 128);

               c-=128;
               KEYCLEAR[0]=0;
               return (int )c;
}

/* the following are used by all the clock functions */

/* a memory saving table for sine cosine */
/* we don't want to haul around an entire math library for */
/* the sake of 184 bytes of data and a parser function     */

/* the divisor is 32767 (a signed int)   */

int sine_cosine[46][2]={
0,    32767,/* 0 degree offset*/
571,  32762,/* 1 degree offset*/
1143, 32747,/* 2 degree offset*/
1714, 32722,/* 3 degree offset*/
2285, 32687,/* 4 degree offset*/
2855, 32642,/* 5 degree offset*/
3425, 32587,/* 6 degree offset*/
3993, 32522,/* 7 degree offset*/
4560, 32448,/* 8 degree offset*/
5125, 32363,/* 9 degree offset*/
5689, 32269,/* 10 degree offset*/
6252, 32164,/* 11 degree offset*/
6812, 32050,/* 12 degree offset*/
7370, 31927,/* 13 degree offset*/
7927, 31793,/* 14 degree offset*/
8480, 31650,/* 15 degree offset*/
9031, 31497,/* 16 degree offset*/
9580, 31335,/* 17 degree offset*/
10125,31163,/* 18 degree offset*/
10667,30981,/* 19 degree offset*/
11206,30790,/* 20 degree offset*/
11742,30590,/* 21 degree offset*/
12274,30381,/* 22 degree offset*/
12803,30162,/* 23 degree offset*/
13327,29934,/* 24 degree offset*/
13847,29696,/* 25 degree offset*/
14364,29450,/* 26 degree offset*/
14875,29195,/* 27 degree offset*/
15383,28931,/* 28 degree offset*/
15885,28658,/* 29 degree offset*/
16383,28377,/* 30 degree offset*/
16876,28086,/* 31 degree offset*/
17363,27787,/* 32 degree offset*/
17846,27480,/* 33 degree offset*/
18323,27165,/* 34 degree offset*/
18794,26841,/* 35 degree offset*/
19259,26509,/* 36 degree offset*/
19719,26168,/* 37 degree offset*/
20173,25820,/* 38 degree offset*/
20620,25464,/* 39 degree offset*/
21062,25100,/* 40 degree offset*/
21497,24729,/* 41 degree offset*/
21925,24350,/* 42 degree offset*/
22347,23964,/* 43 degree offset*/
22761,23570,/* 44 degree offset*/
23169,23169};/*45 degree offset*/

extern int HB[];

/* draw a white box based on byte boundaries */
lbox(x1,y1,x2,y2,bflag)
int x1, y1, x2, y2,bflag;
{
 int temp,packet;

 if(bflag)
 {
    x1*=7;
    x2*=7;
 }

 packet=((x2-x1)+1)/7;
 temp  =x1/7;
  y2++;

 setmem(HB[y1]+temp,packet,0x7f);
 while(y1<y2)
 {
    whiteplot(x1,y1);
    whiteplot(x2,y1);
    y1++;
 }
 setmem(HB[y2-1]+temp,packet,0x7f);
}

drawline(x1,y1,x2,y2)
int x1, y1, x2, y2;
{
	register int dx,dy,ix,iy;
	int e,ei,ed,i;

	dx=x2-x1;
	dy=y2-y1;
	ix=1;
	if(dx<0)
		{ ix=-1;
		  dx=-dx;
		}
	iy=1;
	if(dy<0)
		{ iy=-1;
		  dy=-dy;
		}
	if(dy>dx)
		goto ylin;

	ei=2*dy;
	ed=ei-2*dx;
	e=-dx+ei;
    for(i=1;i<=dx;++i)
        {
        whiteplot(x1,y1);
		x1=x1+ix;
		if(e<0)
			e=e+ei;
		else{
			y1=y1+iy;e=e+ed;
		}
	}
	goto fin;

ylin:

	ei=2*dx;
	ed=ei-2*dy;
	e=-dy+ei;
	for(i=1;i<=dy;++i)
        {
          whiteplot(x1,y1);
		  y1=y1+iy;
		  if(e<0)
			e=e+ei;
		  else{ x1=x1+ix;e=e+ed;}
		}
fin:
;
}

whiteplot(x,y)
{
int xoff, bitoff, point, point1;
char *ptr;

	xoff=x/7;
	bitoff=x%7;

    /*compute point & point1 */

    if (bitoff!=6)
        {
		point=3<<bitoff;
		point1=0;
        }
   else if (xoff != 39)
        {
		point=0x40;
		point1=1;
        }
   else {
		point = 0x60;
		point1=0;
        }

    ptr=(char *)HB[y]+xoff;
    *ptr |= point;
    *ptr++;
    *ptr |= point1;
}
